#pragma once

#include <string>
#include <vector>
#include <fstream>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <unordered_set>

#include "../../Utility/Log/Log.hpp"
#include "../../Utility/Static/Algorithmf.hpp"
#include "../../Utility/Data/NavMessageData/GNSSMesData.hpp"

namespace ns_GNSSMesInput
{
    using namespace ns_Util;
    using namespace ns_Log;

    const std::vector<int> RecordReadFormat648Bit = std::vector<int>({1, 2, -1, 4,
                                                                      -1, 2, -1, 2, -1, 2, -1, 2, -1, 2,
                                                                      19, 19, 19,
                                                                      -4, 19, 19, 19, 19,
                                                                      -4, 19, 19, 19, 19,
                                                                      -4, 19, 19, 19, 19,
                                                                      -4, 19, 19, 19, 19,
                                                                      -4, 19, 19, 19, 19,
                                                                      -4, 19, 19, 19, 19,
                                                                      -4, 19, 19});

    const std::vector<int> RecordReadFormat324Bit = std::vector<int>({
        // TODO
    });

    std::unordered_map<GNSSType, int> BitOfDifType = std::unordered_map<GNSSType, int>(
        {{GNSSType::GPS, 648},
         {GNSSType::Galileo, 648},
         {GNSSType::GLONASS, 324},
         {GNSSType::QZSS, 648},
         {GNSSType::BDS, 648},
         {GNSSType::SBSA, 324},
         {GNSSType::IRNSS, 648}});

    std::unordered_map<GNSSType, int> ReadLineOfDifType = std::unordered_map<GNSSType, int>(
        {{GNSSType::GPS, 8},
         {GNSSType::Galileo, 8},
         {GNSSType::GLONASS, 4},
         {GNSSType::QZSS, 8},
         {GNSSType::BDS, 8},
         {GNSSType::SBSA, 4},
         {GNSSType::IRNSS, 8}});

    class GNSSMesRecordReader
    {
    public:
        GNSSMesRecordReader()
        {
        }

    public:
        static int Read(const std::string &fileName, const std::initializer_list<GNSSType> &catchList,
                        std::vector<std::vector<std::string>>* readResult)
        {
            std::unordered_set<GNSSType> catchs(catchList);
            std::string source = PathUtil::Src(fileName);

            std::ifstream inStream(source);
            if (!inStream.is_open())
            {
                Log(Warnning) << "Open File Failed" << '\n';
                return -1;
            }

            int readState = ReadRecord(inStream, catchs, readResult);

            // TODO

            return readState;
        }

    private:
        static int ReadRecord(std::ifstream &file, const std::unordered_set<GNSSType> &catchs,
                              std::vector<std::vector<std::string>>* readResult)
        {
            std::string buffer;
            // 找ENDOFHEADER
            {
                int tryCount = 100;
                while (true)
                {
                    std::getline(file, buffer);
                    if (buffer.find("END OF HEADER") != buffer.npos)
                        break;

                    tryCount--;
                    if (tryCount < 0)
                    {
                        return FileReadStateType::FileReadDefault;
                    }

                    buffer.clear();
                }
            }

            while (file.rdstate() != std::ios::eofbit)
            {
                // 先找归属哪个卫星系统
                char tmp;
                file.get(tmp);

                GNSSType type = GNSSTypeUtil::GetGNSSTypeByMark(tmp);
                if (type == GNSSType::DefaultGNSSType)
                {
                    continue;
                }

                // 文件指针前移一个单位
                file.seekg(-1, std::ios::cur);

                int readState;
                switch (type)
                {
                case GNSSType::GPS:
                    readState = GPSRecordRead(file, catchs, readResult);
                    break;
                case GNSSType::BDS:
                    readState = BDSRecordRead(file, catchs, readResult);
                    break;
                case GNSSType::Galileo:
                    readState = GalileoRecordRead(file, catchs, readResult);
                    break;
                case GNSSType::IRNSS:
                    readState = IRNSSRecordRead(file, catchs, readResult);
                    break;
                case GNSSType::GLONASS:
                    readState = GLONASSRecordRead(file, catchs, readResult);
                    break;
                case GNSSType::QZSS:
                    readState = QZSSRecordRead(file, catchs, readResult);
                    break;
                case GNSSType::SBSA:
                    readState = SBSARecordRead(file, catchs, readResult);
                    break;
                default:
                    break;
                }
            }

            return 0;
        }

        static int GPSRecordRead(std::ifstream &file, const std::unordered_set<GNSSType> &catchs,
                                 std::vector<std::vector<std::string>>* readResult)
        {
            std::string buffer;
            FileReadStateType readState = RecordRead(file, GNSSType::GPS, buffer, catchs);

            if (readState == FileReadStateType::FileReadIgnore)
                return readState;

            std::vector<std::string> ins;

            int pos = 0;
            for (auto e : RecordReadFormat648Bit)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(buffer.begin() + pos, buffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult->push_back(ins);

            return FileReadStateType::FileReadSuccess;
        }

        static int BDSRecordRead(std::ifstream &file, const std::unordered_set<GNSSType> &catchs,
                                 std::vector<std::vector<std::string>>* readResult)
        {
            std::string buffer;
            FileReadStateType readState = RecordRead(file, GNSSType::BDS, buffer, catchs);

            if (readState == FileReadStateType::FileReadIgnore)
                return readState;

            std::vector<std::string> ins;

            int pos = 0;
            for (auto e : RecordReadFormat648Bit)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(buffer.begin() + pos, buffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult->push_back(ins);

            return FileReadStateType::FileReadSuccess;
        }

        static int GalileoRecordRead(std::ifstream &file, const std::unordered_set<GNSSType> &catchs,
                                     std::vector<std::vector<std::string>>* readResult)
        {
            std::string buffer;
            FileReadStateType readState = RecordRead(file, GNSSType::Galileo, buffer, catchs);

            if (readState == FileReadStateType::FileReadIgnore)
                return readState;

            std::vector<std::string> ins;

            int pos = 0;
            for (auto e : RecordReadFormat648Bit)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(buffer.begin() + pos, buffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult->push_back(ins);

            return FileReadStateType::FileReadSuccess;
        }

        static int IRNSSRecordRead(std::ifstream &file, const std::unordered_set<GNSSType> &catchs,
                                   std::vector<std::vector<std::string>>* readResult)
        {
            std::string buffer;
            FileReadStateType readState = RecordRead(file, GNSSType::IRNSS, buffer, catchs);

            if (readState == FileReadStateType::FileReadIgnore)
                return readState;

            std::vector<std::string> ins;

            int pos = 0;
            for (auto e : RecordReadFormat648Bit)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(buffer.begin() + pos, buffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult->push_back(ins);

            return FileReadStateType::FileReadSuccess;
        }

        static int GLONASSRecordRead(std::ifstream &file, const std::unordered_set<GNSSType> &catchs,
                                     std::vector<std::vector<std::string>>* readResult)
        {
            std::string buffer;
            FileReadStateType readState = RecordRead(file, GNSSType::GLONASS, buffer, catchs);

            if (readState == FileReadStateType::FileReadIgnore)
                return readState;

            std::vector<std::string> ins;

            int pos = 0;
            for (auto e : RecordReadFormat324Bit)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(buffer.begin() + pos, buffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult->push_back(ins);

            return FileReadStateType::FileReadSuccess;
        }

        static int QZSSRecordRead(std::ifstream &file, const std::unordered_set<GNSSType> &catchs,
                                  std::vector<std::vector<std::string>>* readResult)
        {
            std::string buffer;
            FileReadStateType readState = RecordRead(file, GNSSType::QZSS, buffer, catchs);

            if (readState == FileReadStateType::FileReadIgnore)
                return readState;

            std::vector<std::string> ins;

            int pos = 0;
            for (auto e : RecordReadFormat648Bit)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(buffer.begin() + pos, buffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult->push_back(ins);

            return FileReadStateType::FileReadSuccess;
        }

        static int SBSARecordRead(std::ifstream &file, const std::unordered_set<GNSSType> &catchs,
                                  std::vector<std::vector<std::string>>* readResult)
        {
            std::string buffer;
            FileReadStateType readState = RecordRead(file, GNSSType::SBSA, buffer, catchs);

            if (readState == FileReadStateType::FileReadIgnore)
                return readState;

            std::vector<std::string> ins;

            int pos = 0;
            for (auto e : RecordReadFormat324Bit)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(buffer.begin() + pos, buffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult->push_back(ins);

            return FileReadStateType::FileReadSuccess;
        }

        static FileReadStateType RecordRead(std::ifstream &file, GNSSType type, std::string &buffer, const std::unordered_set<GNSSType> &catchs)
        {
            std::string _buffer;
            int lineSize = ReadLineOfDifType[type];

            for (int i = 0; i < lineSize; i++)
            {
                std::getline(file, _buffer);
                _buffer.resize(80);
                buffer += _buffer;
                _buffer.clear();
            }

            if (catchs.find(type) == catchs.end())
                return FileReadStateType::FileReadIgnore;

            return FileReadStateType::FileReadSuccess;
        }
    };
}